import type { AxiosResponse, InternalAxiosRequestConfig, RawAxiosRequestHeaders } from 'axios';
import { errorNotification } from '@/helpers/antd/notification';

import router from '@/routers';
import CommonPageName from '@/routers/common-page-name';

import { useAuthenticationStore } from '@/stores/auth';
import { getAppConfig } from '@/utils/env-utils';

import axios from 'axios';
import qs from 'qs';
import ApiResultCode from './api-result-code';
import RequestHeader from './header';

const appConfig = getAppConfig();

const instance = axios.create({
  baseURL: appConfig.apiBaseUrl + appConfig.apiVersion,
  timeout: appConfig.timeout,
  headers: {
    [RequestHeader.CONTENT_TYPE]: RequestHeader.CONTENT_TYPE_APPLICATION_JSON,
  },
  paramsSerializer: {
    serialize: params => qs.stringify(params, {
      arrayFormat: 'brackets',
      skipNulls: true,
    }),
  },
  responseType: 'json',
  validateStatus: () => true,
});

let authenticationStore: Nullable<ReturnType<typeof useAuthenticationStore>> = null;

instance.interceptors.request.use(
  (config: InternalAxiosRequestConfig) => {
    if (authenticationStore == null) {
      authenticationStore = useAuthenticationStore();
    }
    if (authenticationStore.isLogin && config.headers) {
      config.headers[RequestHeader.AUTHORIZATION] = `Bearer ${authenticationStore.accessToken}`;
    }
    const url = decodeURIComponent(config.url as string);
    config.url = url;
    return config;
  },
  error => {
    const { message } = error;
    errorNotification('请求发起异常', message);
    return Promise.reject(message);
  },
);

instance.interceptors.response.use(
  (response: AxiosResponse<ApiResponse>) => {
    const data = response.data;
    if (!data) {
      return Promise.reject({
        code: response.status,
        message: response.statusText,
      });
    }
    const { code, message } = data;
    if (code === ApiResultCode.SUCCESS) {
      return response;
    }
    if (code === ApiResultCode.UNAUTHORIZED) {
      errorNotification('请求发起异常', message);
      authenticationStore.clearAuthInfoAction();
      router.replace({
        name: CommonPageName.LOGIN,
      });
    }
    return Promise.reject(data);
  },
  error => {
    return Promise.reject(error);
  },
);

export function post<T = any, D = Recordable>(
  url: string,
  data: D,
  params: Recordable = {},
  headers: RawAxiosRequestHeaders = {},
) {
  return instance.post<ApiResponse<T>, AxiosResponse<ApiResponse<T>, D>, D>(url, data, {
    headers,
    params,
  }).then(response => response.data);
}

export function del<T = any>(
  url: string,
  params: Recordable = {},
  headers: RawAxiosRequestHeaders = {},
) {
  return instance.delete<ApiResponse<T>>(url, {
    headers,
    params,
  }).then(response => response.data);
}

export function put<T = any, D = Recordable>(
  url: string,
  data: D,
  params: Recordable = {},
  headers: RawAxiosRequestHeaders = {},
) {
  return instance.put<ApiResponse<T>, AxiosResponse<ApiResponse<T>, D>, D>(url, data, {
    headers,
    params,
  }).then(response => response.data);
}

export function get<T = any>(
  url: string,
  params: Recordable = {},
  headers: RawAxiosRequestHeaders = {},
) {
  return instance.get<ApiResponse<T>>(url, {
    headers,
    params,
  }).then(response => response.data);
}
